from django.shortcuts import render
from django.views import View
from utils.verifyUtil import ImageVerify  # 生成验证码
import io  # 流模块
from django_redis import get_redis_connection  # 指定连接池
from config.dbs.redis_rev import LOGIN_KEY_TEMPLATE, EXPIRE_TIME  # 键，过期时间
from django.http import HttpResponse

from django.contrib.auth.models import User  # auth自带的用户表
from rest_framework.viewsets import ReadOnlyModelViewSet, ModelViewSet  # 只读视图集类
from .serializers import *
from rest_framework.permissions import IsAuthenticated  # 权限
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
from rest_framework.response import Response  # 响应
from rest_framework.decorators import action  # 行为路由装饰器
# from utils.permission import ActiveUserPermission, wrap_permission, TeacherPermission
from utils.permission import *

from fdfs_client.client import Fdfs_client, get_tracker_conf  # FastDFS
from config.fastdfsConfig import FASTDFS_SERVER_DOMAIN  # 部署代理的位置
import logging  # 日志器
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR

# 创建日志器
logger = logging.getLogger(__name__)  # 创建一个记录邮箱发送的日志器

tracker_path = get_tracker_conf('utils/fastdfs/client.conf')  # tracker配置文件路径
client = Fdfs_client(tracker_path)  # 客户端对象


# Create your views here.
class ImageVerifyView(View):
    """
    图片验证码的视图类
    get请求
    返回验证码图片
    """

    def get(self, request, uuid):
        """
        返回验证码
        :param request: 请求对象
        :param uuid: 客户端唯一标识码
        :return:
        """
        imgVerify = ImageVerify()  # 实例化类
        img, code = imgVerify.verify_code()  # 拆包

        # 流存储，临时存储
        img_bytes = io.BytesIO()  # 字节流仓库
        img.save(img_bytes, format='PNG')  # 存在流仓库当中png格式
        image_bytes = img_bytes.getvalue()  # 获取图片

        cache = get_redis_connection(alias='verify_codes')  # 1号库
        cache.set(LOGIN_KEY_TEMPLATE % uuid, code, EXPIRE_TIME)

        return HttpResponse(image_bytes, content_type='image/png')


# 用户的视图集
class UserViewSet(ModelViewSet):
    queryset = User.objects.filter(is_active=1)  # 查询集
    serializer_class = UserSerializer  # 需要使用的序列化器
    # 要求用户先登录，才能够访问该视图类
    permission_classes = [IsAuthenticated]

    # 根据不同的行为使用不同的序列化器
    def get_serializer(self, *args, **kwargs):
        if self.action == 'password':
            return UpdatePasswordSerializer(*args,**kwargs)
        return self.serializer_class(*args,**kwargs)


    @wrap_permission(TeacherPermission)
    def list(self, request, *args, **kwargs):
        return ReadOnlyModelViewSet.list(self, request, *args, **kwargs)

    @wrap_permission(ActiveUserPermission)
    def retrieve(self, request, *args, **kwargs):
        return ReadOnlyModelViewSet.retrieve(self, request, *args, **kwargs)

    # 重写修改的方法
    @wrap_permission(ActiveUserPermission)
    def update(self, request, pk):
        try:
            user = self.get_queryset().get(id=pk)
        except User.DoesNotExist:  # 针对于没查询到，没有模型对象才会抛出的异常
            return Response(status=HTTP_404_NOT_FOUND)

        # 得到用户输入的数据，进行反序列化操作
        user_serializer = self.get_serializer(user, data=request.data)
        # 校验
        user_serializer.is_valid(raise_exception=True)
        # 保存
        user_serializer.save()

        user_detail = request.data.get('userdetail')
        # 判断用户是否传入详情信息
        if user_detail:
            # 有
            if hasattr(user, 'userdetail'):
                # 如果有详情数据，做修改
                user_detail_serializer = UserDetailSerializer(user.userdetail, data=user_detail)
            else:
                # 没有 添加
                user_detail['user'] = pk  # 指定操作的用户
                user_detail_serializer = UserDetailSerializer(data=user_detail)
            user_detail_serializer.is_valid(raise_exception=True)
            user_detail_serializer.save()

            user_serializer.data['userdetail'] = user_detail_serializer.data  # 字典赋值

        return Response(user_serializer.data)

    # 头像上传
    @action(methods=['post'], detail=True)  # 访问
    def avatar(self, request, pk):
        try:
            user = self.get_queryset().get(id=pk)  # 哪个用户
        except User.DoesNotExist:  # 没获取到数据
            return Response(status=HTTP_404_NOT_FOUND)

        # 得到上传的头像
        file = request.FILES.get('file')
        if not file or file.content_type not in ('image/jpeg', 'image/png', 'image/gif'):
            return Response(status=HTTP_400_BAD_REQUEST)

        try:
            images_ext_name = file.name.split('.')[-1]
        except Exception as e:
            logger.info('图片扩展名异常：%s' % e)
            images_ext_name = 'png'

        # 上传图片
        try:
            upload_res = client.upload_by_buffer(file.read(), file_ext_name=images_ext_name)
        except Exception as e:
            logger.error('图片上传异常：%s' % e)
            return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)

        else:
            if upload_res.get('Status') != 'Upload successed.':
                logger.warning('图片上传失败')
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)

            image_name = upload_res.get('Remote file_id').decode()  # 解码
            image_url = FASTDFS_SERVER_DOMAIN + image_name  # 完整的图片的路由地址

            if hasattr(user, 'userdetail'):
                # 有详情数据，已经上传过头像
                user_detail = user.userdetail  # 反向访问
                user_detail.avatar = image_url
                user_detail.save()
            else:
                UserDetail.objects.create(avatar=image_url, user=user)

            return Response({'data':image_url})

    # 密码修改
    @action(methods=['put'], detail=True)  # 访问
    def password(self, request, pk):
        try:
            user = self.get_queryset().get(id=pk)  # 哪个用户
        except User.DoesNotExist:  # 没获取到数据
            return Response(status=HTTP_404_NOT_FOUND)

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        password = request.data['password']
        new_password = request.data['new_password']
        if user.check_password(password):
            user.set_password(new_password)
            user.save()
            return Response({'msg':'修改成功'})
        else:
            return Response(status=HTTP_400_BAD_REQUEST)

from rest_framework_extensions.cache.mixins import CacheResponseMixin  # 加载drf配置
# 行政区的视图集
class AreaViewSet(CacheResponseMixin,ModelViewSet):
    queryset = Area.objects.all()  # 查询集
    serializer_class = AreaSerializer  # 需要使用的序列化器
    # 要求用户先登录，才能够访问该视图类
    # permission_classes = [IsAuthenticated]

    # 自定义查询集
    def get_queryset(self):
        if self.action == 'list':
            return Area.objects.filter(parent=None)  # 一级行政区
        else:
            return self.queryset

    # 自定义序列化器
    def get_serializer_class(self):
        if self.action == 'retrieve':
            return ParentSerializer
        else:
            return AreaSerializer


    # 管理员创建
    @wrap_permission(RootPermission)
    def create(self, request, *args, **kwargs):
        return ModelViewSet.create(self, request, *args, **kwargs)

    # 修改
    @wrap_permission(RootPermission)
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    # 删除
    @wrap_permission(RootPermission)
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)


# 收货地址的视图集
class AddressViewSet(ModelViewSet):
    # queryset = Area.objects.all()  # 查询集
    serializer_class = AddressSerializer  # 需要使用的序列化器
    # 要求用户先登录，才能够访问该视图类
    permission_classes = [IsAuthenticated]

    # 自定义查询集
    def get_queryset(self):
        # 查询所有已添加的收货地址
        return self.request.user.address_set.filter(is_delete=False)

    @auto_user
    def create(self, request, *args, **kwargs):
        max_count = 5
        if self.get_queryset().count() >= max_count:
            return Response({'detail':f'收货地址数量超过{max_count}条'},status=HTTP_400_BAD_REQUEST)
        return ModelViewSet.create(self, request, *args, **kwargs)

    # 本人才能修改收货地址
    @update_auto_user
    def update(self, request, *args, **kwargs):
        return ModelViewSet.update(self, request, *args, **kwargs)

    # 本人才能删除自己的收货地址
    @destroy_auto_user
    def destroy(self, request, *args, **kwargs):
        return ModelViewSet.destroy(self, request, *args, **kwargs)






